﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace SGH
{
    class Pattern
    {
        public int[,] p;//生成的排样结果，第一维记录的是毛坯序号，第二维存储相应的毛坯个数
        double[,] F;
        int[,] G;
        int[,] R;
        int[,] D;
        public List<int[]> layout;//生成的排样图，记录条带的排样，int[]中存储毛坯序号、条带排数、条带方向、条带长度
        int[,,] N;
        int length;
        int width;
        Stripe stripe;
       public int typeNum;
        int rowNum;
        double[] value;
        int[] restDemand;
        int[] blankId;
        int[] diameter;
        /// <summary>
        /// 是否有余料
        /// </summary>
        public bool IsOffcut = false;
        int min;
        public Pattern(Global global)
        {
            length = Constant.sheetLength;
            width = Constant.sheetWidth;
            stripe = global.stripe;
            typeNum = global.CISET.Count;//ciset中毛坯的种数
            rowNum = Constant.blankRow;
            G = new int[length + 1, width + 1];
            R = new int[length + 1, width + 1];
            D = new int[length + 1, width + 1];
            Init();
            p = new int[typeNum, 2];
            F = new double[length + 1, width + 1];
            N = new int[length + 1, width + 1, Constant.blankTypeNum];
            value = new double[typeNum];
            restDemand = new int[typeNum];
            blankId = new int[typeNum];
            diameter = new int[typeNum];
            for (int i = 0; i < typeNum; i++)
            {
                int id = global.CISET[i][0];
                blankId[i] = id;
                restDemand[i] = global.CISET[i][1];
                value[i] = global.blankValue[id];
                diameter[i] = Constant.diameter[id];
            }
            //value = Constant.blankValue;//要改为修正后的价值
            //restDemand = Constant.demand;//要改为剩余毛坯
        }

        public void Init()
        {
            for (int i = 0; i < length; i++)
            {
                for (int j = 0; j < width; j++)
                {
                    G[i, j] = -1;
                    R[i, j] = -1;
                    D[i, j] = -1;
                }
            }
        }

        public void DoPattern()
        {
            min = 0;
            if (diameter.Length == 1)
            {
                min = diameter[0];
            }
            min = Method.getMin(diameter);
            for (int l = min; l <= length; l++)
            {
                for (int w = min; w <= width; w++)
                {
                    if (F[l - 1, w] >= F[l, w - 1])
                    {
                        F[l, w] = F[l - 1, w];
                        for (int i = 0; i < typeNum; i++)
                        {
                            N[l, w, i] = N[l - 1, w, i];
                        }
                    }
                    else
                    {
                        F[l, w] = F[l, w - 1];
                        for (int i = 0; i < typeNum; i++)
                        {
                            N[l, w, i] = N[l, w - 1, i];
                        }
                    }

                    for (int t = 0; t < typeNum; t++)
                    {
                        ImprovePattern(l, w, t);
                    }

                    if (!Constant.IsControl) continue;


                    

                        if (!Constant.IsUseControl) continue;
                        //当到最后的步长时，开始进行余料控制
                        if (l == length && w == width)
                        {
                            for (int t = 0; t < typeNum; t++)
                            {
                                ImproveOffcutPattern(l, w, t);
                            }
                        }
                    
                }
            }


            seekBack();
            setP();
        }

        private void ImprovePattern(int x, int y, int i)
        {
            //横向
            for (int r = 0; r < rowNum; r++)
            {
                var stripeWidth = stripe.width[blankId[i], r];
                if (y < stripeWidth) break;
                else patIn(x, y, i, r, 0);
            }


            //余料控制则不排纵向条带
            if (Constant.IsControl) return;
            //纵向
            for (int r = 0; r < rowNum; r++)
            {
                var stripeWidth = stripe.width[blankId[i], r];
                if (x < stripeWidth) break;
                else patIn(x, y, i, r, 1);
            }


        }

        /// <summary>
        /// 余料排样
        /// </summary>
        /// <param name="x"></param>
        /// <param name="y"></param>
        /// <param name="t"></param>
        private void ImproveOffcutPattern(int x, int y, int t)
        {
            var row = stripe.OffcutWidth.Length / Constant.blankTypeNum;
            //纵向
            for (int r = 0; r < row; r++)
            {
                var offcutWidth = stripe.OffcutWidth[blankId[t], r];
                if (offcutWidth > Constant.OffcutWidthLimit) continue;
                if (x < offcutWidth) break;
                else patIn(x, y, t, r, 2);
            }
        }

        private int patIn(int x, int y, int type, int r, int direction)
        {
            int rx = -1;
            int ry = -1;
            int stripeBlankNum = 0;
            if (direction == 1)//y方向
            {
                rx = x - stripe.width[blankId[type], r];
                ry = y;
                stripeBlankNum = stripe.stripe[blankId[type], y, r];
            }
            else if (direction == 0)//x方向
            {
                rx = x;
                ry = y - stripe.width[blankId[type], r];
                stripeBlankNum = stripe.stripe[blankId[type], x, r];
            }
            else if (direction == 2)//余料控制
            {
                rx = x - stripe.OffcutWidth[blankId[type], r];
                ry = y;
                stripeBlankNum = stripe.OffcutStripe[blankId[type], y, r];
            }

            int[] b = new int[typeNum];
            if (value[type] * stripeBlankNum + F[rx, ry] < F[x, y]) return 0;
            else if (stripeBlankNum + N[rx, ry, type] > restDemand[type]) return 0;
            else
            {
                double tempvalue = 0.0;
                for (int i = 0; i < typeNum; i++)
                {
                    int num = N[rx, ry, i];
                    if (restDemand[i] < num) b[i] = restDemand[i];
                    else b[i] = num;
                }
                //余料条带生成，毛坯数不加入排样方案
                //if (direction != 2)
                {
                    b[type] += stripeBlankNum;
                }

                for (int i = 0; i < typeNum; i++)
                {
                    tempvalue += value[i] * b[i];
                }
                if (tempvalue > F[x, y])
                {
                    F[x, y] = tempvalue;
                    for (int i = 0; i < typeNum; i++)
                    {
                        N[x, y, i] = b[i];
                    }
                }
                G[x, y] = blankId[type];
                R[x, y] = r;
                D[x, y] = direction;
                return 0;
            }
        }

        private void setP()
        {
            for (int i = 0; i < typeNum; i++)
            {
                p[i, 0] = blankId[i];
                p[i, 1] = N[length, width, i];
                foreach (var item in layout)
                {
                    if (item[2] != 2) continue;
                    var id = item[0];
                    if (id != blankId[i]) continue;
                    var num = item[4];
                    p[i, 1] = p[i, 1] -num;
                }
            }

        }
        //回溯
        private void seekBack()
        {
            layout = new List<int[]>();

            int x = length;
            int y = width;
            while (x > min && y > min)
            {
                if (G[x, y] == -1)
                {
                    x--;
                    if (G[x, y] == -1)
                    {
                        y--;
                    }
                    continue;
                }
                /*
            * 毛坯id：   s[0] 
            * 毛坯排数:  s[1] 
            * 条带方向： s[2] 
            * 条带长度： s[3] 
            * 毛坯个数： s[4]
            */
                int[] temp = new int[5];
                temp[0] = G[x, y];
                temp[1] = R[x, y];
                temp[2] = D[x, y];
                int n = 0;
                int w = stripe.width[temp[0], temp[1]];
                if (D[x, y] == 0)
                {
                    temp[3] = x;
                    n = stripe.stripe[temp[0], x, temp[1]];
                    y = y - w;
                }
                else if (D[x, y] == 1)
                {
                    temp[3] = y;
                    n = stripe.stripe[temp[0], y, temp[1]];
                    x = x - w;
                }
                else if ((D[x, y] == 2))
                {
                    temp[3] = y;
                    n = stripe.OffcutStripe[temp[0], y, temp[1]];
                    x = x - stripe.OffcutWidth[temp[0], temp[1]];
                    IsOffcut = true;
                }
                temp[4] = n;

                layout.Add(temp);
            }
        }
    }
}
